#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高级AT指令控制器
功能：支持主题管理、多指令序列、数据解析配置
版本：2.0 加密保护版
作者：Zack Studio
"""

import time
import csv
import json
import re
from datetime import datetime
from typing import Dict, List, Optional, Tuple, Any
import os
import sys
import threading
import subprocess
try:
    import pandas as pd
    import openpyxl
    PANDAS_AVAILABLE = True
except ImportError:
    PANDAS_AVAILABLE = False

# 导入配置管理器
from src.managers.config_manager import config_manager
from src.managers.topic_manager import TopicManager
from src.models.test_topic import TestTopic
from src.monitors.vbat_monitor import VBATMonitor
from src.controllers.serial_controller import SerialController
from src.parsers.at_command_parser import ATCommandParser

# 导入加密保护模块
sys.path.append(os.path.join(os.path.dirname(__file__), 'src', 'utils'))
try:
    from encryption import anti_decompile, protected_startup
    ENCRYPTION_AVAILABLE = True
except ImportError:
    ENCRYPTION_AVAILABLE = False

# 启动保护检查
if ENCRYPTION_AVAILABLE:
    anti_decompile.protect_startup()

class AdvancedATController:
    """高级AT指令控制器"""
    def __init__(self):
        # 初始化端口控制器
        self.serial_controller = SerialController()
        
        # 初始化主题管理器
        self.topic_manager = TopicManager()
        
        # 其他属性
        self.test_results: List[Dict] = []
        self.execution_history = []
        
        # 初始化VBAT监控模块
        self.vbat_monitor = VBATMonitor()
        
        # 初始化AT命令解析器
        self.at_parser = ATCommandParser()

        # 紧急停止标志
        self.emergency_stop_flag = False

        self.load_relay_config()
        self.load_vbat_config()
    
    # 端口控制方法通过serial_controller调用
    def list_available_ports(self) -> List[str]:
        """列出所有可用的端口"""
        return self.serial_controller.list_available_ports()
    
    def list_available_ports_with_info(self) -> List[Dict[str, Any]]:
        """列出所有可用的端口及其详细信息"""
        return self.serial_controller.list_available_ports_with_info()
    
    def connect(self, port: str, baudrate: int = 115200, timeout: float = 1.0) -> bool:
        """连接到端口"""
        return self.serial_controller.connect(port, baudrate, timeout)
    
    def connect_with_baudrate_selection(self, port: str) -> bool:
        """连接端口时选择波特率"""
        return self.serial_controller.connect_with_baudrate_selection(port)
    
    def disconnect(self):
        """断开端口连接"""
        self.serial_controller.disconnect()
    
    def configure_relay_control(self):
        """配置继电器控制参数"""
        self.serial_controller.configure_relay_control()
        # 保存配置
        self.save_relay_config()
    
    def set_relay_state(self, state: bool):
        """设置继电器状态
        Args:
            state: True=开启继电器, False=关闭继电器
        """
        self.serial_controller.set_relay_state(state)
    
    def toggle_relay(self):
        """切换继电器状态"""
        self.serial_controller.toggle_relay()
    
    def wait_for_boot_complete(self) -> bool:
        """等待开机完成
        Returns:
            True: 开机成功，收到关键字
            False: 开机超时，未收到关键字
        """
        return self.serial_controller.wait_for_boot_complete()
    
    def send_command(self, command: str, delay_ms: int = 0) -> str:
        """发送AT指令并返回响应"""
        return self.serial_controller.send_command(command, delay_ms)
    
    def create_topic(self, name: str) -> bool:
        """创建新主题"""
        return self.topic_manager.create_topic(name)

    def delete_topic(self, name: str) -> bool:
        """删除主题"""
        return self.topic_manager.delete_topic(name)

    def list_topics(self):
        """列出所有主题"""
        self.topic_manager.list_topics()

    def view_topic_details(self, topic_name: str):
        """查看主题详细内容"""
        self.topic_manager.view_topic_details(topic_name)
    

    
    def save_relay_config(self):
        """保存继电器配置到文件"""
        self.serial_controller.save_relay_config()

    def load_vbat_config(self):
        """加载VBAT监控配置"""
        self.vbat_monitor.load_vbat_config()

    def save_vbat_config(self):
        """保存VBAT监控配置"""
        self.vbat_monitor.save_vbat_config()

    def configure_vbat_monitor(self):
        """配置VBAT监控参数"""
        self.vbat_monitor.configure_vbat_monitor(self)
         
    def load_relay_config(self):
        """从文件加载继电器配置"""
        self.serial_controller.load_relay_config()
        print("✅ 继电器配置已加载")

    def save_execution_history(self, topic_name: str, results: List[Dict]):
        """保存执行历史到文件和表格"""
        try:
            timestamp = datetime.now()
            timestamp_str = timestamp.isoformat()
            
            # 获取当前连接信息
            port = '未知'
            baudrate = 0
            if hasattr(self.serial_controller, 'serial_port') and self.serial_controller.serial_port:
                if hasattr(self.serial_controller.serial_port, 'port'):
                    port = self.serial_controller.serial_port.port
                if hasattr(self.serial_controller.serial_port, 'baudrate'):
                    baudrate = self.serial_controller.serial_port.baudrate
            
            # 简洁保存执行历史JSON
            execution_data = {
                '时间': timestamp_str,
                '主题': topic_name,
                '命令': [
                    {
                        'cmd': r.get('command', ''),
                        '结果': r.get('response', '')[:50],
                        '解析': r.get('parsed', {})
                    }
                    for r in results if r.get('command', '').strip()
                ]
            }
            
            # 读取现有历史
            history = []
            if os.path.exists('execution_history.json'):
                try:
                    with open('execution_history.json', 'r', encoding='utf-8') as f:
                        history = json.load(f)
                except:
                    history = []
            
            # 添加新记录
            history.append(execution_data)
            
            # 保存JSON文件
            with open('execution_history.json', 'w', encoding='utf-8') as f:
                json.dump(history, f, ensure_ascii=False, indent=2)
            
            # 简洁保存执行命令表格
            if PANDAS_AVAILABLE:
                # 精简的命令记录
                commands_data = []
                for i, result in enumerate(results, 1):
                    commands_data.append({
                        '时间': timestamp_str,
                        '命令': result.get('command', ''),
                        '结果': result.get('response', '')[:100]  # 限制长度
                    })
                
                # 保存命令表格到CSV
                commands_df = pd.DataFrame(commands_data)
                commands_filename = f"cmds_{timestamp.strftime('%m%d_%H%M')}.csv"
                commands_df.to_csv(commands_filename, index=False, encoding='utf-8-sig')
                
                # 简洁保存解析数据
                parsed_data = []
                for result in results:
                    parsed = result.get('parsed', {})
                    if parsed:
                        row = {
                            '时间': timestamp_str,
                            '命令': result.get('command', '')
                        }
                        # 只添加有效解析值
                        for key, value in parsed.items():
                            if value is not None and str(value).strip():
                                row[key] = str(value)
                        if len(row) > 2:  # 确保有解析数据
                            parsed_data.append(row)
                
                if parsed_data:
                    # 创建简洁Excel文件
                    parsed_df = pd.DataFrame(parsed_data)
                    parsed_filename = f"data_{timestamp.strftime('%m%d_%H%M')}.xlsx"
                    parsed_df.to_excel(parsed_filename, index=False)
                
                print("✅ 已保存")
                print(f"   命令: {commands_filename}")
                if parsed_data:
                    print(f"   数据: {parsed_filename}")
            else:
                # 无pandas时的简化CSV保存
                commands_filename = f"cmds_{timestamp.strftime('%m%d_%H%M')}.csv"
                with open(commands_filename, 'w', newline='', encoding='utf-8-sig') as f:
                    writer = csv.writer(f)
                    writer.writerow(['时间', '命令', '结果'])
                    for result in results:
                        writer.writerow([
                            timestamp_str,
                            result.get('command', ''),
                            result.get('response', '')[:100]
                        ])
                print(f"✅ 已保存: {commands_filename}")
                
        except Exception as e:
            print(f"❌ 保存执行历史失败: {e}")
            import traceback
            traceback.print_exc()
    
    def view_execution_history(self):
        """查看执行历史"""
        try:
            if not os.path.exists('execution_history.json'):
                print("⚠️  没有找到执行历史文件")
                return
            
            with open('execution_history.json', 'r', encoding='utf-8') as f:
                history = json.load(f)
            
            if not history:
                print("⚠️  没有执行历史记录")
                return
            
            print("📊 历史记录")
            print("=" * 40)
            
            for i, record in enumerate(history, 1):
                print(f"\n{i}. {record['时间'][:16]} {record['主题']}")
                
                # 显示命令和结果
                for cmd in record['命令']:
                    print(f"   {cmd['cmd']} -> {cmd['结果']}")
                    if cmd['解析']:
                        for key, value in cmd['解析'].items():
                            print(f"     {key}: {value}")
            
            input("\n按回车键返回...")
            
        except Exception as e:
            print(f"❌ 读取执行历史失败: {e}")
            input("按回车键继续...")

    def configure_parse_patterns(self, topic_name: str):
        """配置主题的解析模式（代理方法）"""
        self.topic_manager.configure_parse_patterns(topic_name)

    def configure_loop_parameters(self, topic_name: str):
        """配置主题的循环参数（代理方法）"""
        self.topic_manager.configure_loop_parameters(topic_name)

    def configure_topic(self, topic_name: str):
        """配置主题（代理方法）"""
        self.topic_manager.configure_topic(topic_name)
    
    def _add_template_pattern(self, topic: TestTopic):
        """使用模板快速添加解析模式"""
        templates = [
            {"name": "电压值", "pattern": r"\+CBC:\s*(\d+)", "type": "int", "desc": "提取+CBC后的电压值"},
            {"name": "信号强度", "pattern": r"\+CSQ:\s*(\d+)", "type": "int", "desc": "提取+CSQ后的信号强度"},
            {"name": "版本号", "pattern": r"Revision:\s*(\S+)", "type": "str", "desc": "提取版本信息"},
            {"name": "电池电量", "pattern": r"(\d+)%", "type": "int", "desc": "提取百分比电量"},
            {"name": "温度值", "pattern": r"(\d+\.?\d*)°C", "type": "float", "desc": "提取温度值"},
            {"name": "IMEI", "pattern": r"\+GSN:\s*(\d+)", "type": "str", "desc": "提取IMEI号码"},
            {"name": "一键VBAT", "pattern": r"VBAT,\s*(\d+)", "type": "int", "desc": "一键提取VBAT电压值"}
        ]
        
        print("\n🎯 快速模板添加")
        print("=" * 50)
        for i, template in enumerate(templates, 1):
            print(f"{i}. {template['name']} - {template['desc']}")
            print(f"   正则: {template['pattern']} ({template['type']})")
            print()
        
        try:
            choice = int(input("选择模板(1-7): ").strip())
            if 1 <= choice <= len(templates):
                template = templates[choice-1]
                topic.add_parse_pattern(template['name'], template['pattern'], template['type'])
                print(f"✅ 已添加模板: {template['name']}")
            else:
                print("❌ 无效选择")
        except ValueError:
            print("❌ 请输入有效数字")
    





    

    


    def run_topic_test(self, topic_name: str, loop_count: int = None, loop_delay: int = None) -> List[Dict]:
        """运行主题测试，支持指令级别的循环
        
        每条指令可以独立设置循环次数，通过loop_count参数控制
        主题级别的循环控制整个指令序列的重复执行
        """
        topic = self.topic_manager.get_topic(topic_name)
        if not topic:
            print(f"⚠️ 主题 '{topic_name}' 不存在")
            return []
        if not topic.commands:
            print(f"⚠️ 主题 '{topic_name}' 没有指令")
            return []
        
        if not self.serial_controller.is_connected:
            print("❌ 未连接到端口")
            return []
        
        # 使用主题配置或参数
        actual_loop_count = loop_count if loop_count is not None else topic.loop_count
        actual_loop_delay = loop_delay if loop_delay is not None else topic.loop_delay_ms
        
        # 如果主题禁用循环，强制单次执行，但允许参数覆盖
        if not topic.loop_enabled and loop_count is None:
            actual_loop_count = 1
            
        results = []
        total_commands = len(topic.commands)
        
        print(f"\n🚀 开始运行主题测试: {topic_name}")
        print(f"📊 指令数: {total_commands}, 主题循环: {actual_loop_count}次, 间隔: {actual_loop_delay}ms")
        
        # 显示每条指令的循环次数
        print("📋 指令循环配置:")
        for i, cmd in enumerate(topic.commands, 1):
            loop_times = cmd.get("loop_count", 1)
            print(f"   {i}. {cmd['command']} → 执行{loop_times}次")
        
        if topic.loop_enabled:
            print(f"🔁 主题循环执行已启用")
        else:
            print(f"➡️ 主题单次执行模式")
        print("="*60)
        
        # 循环前的继电器状态设置
        if self.serial_controller.relay_control_enabled and self.serial_controller.relay_open_before_loop:
            self.set_relay_state(True)  # 开始测试时打开继电器
            
            # 开机检测逻辑
            if self.serial_controller.boot_check_enabled:
                print("🔍 正在检测开机状态...")
                boot_success = self.wait_for_boot_complete()
                if boot_success:
                    print("✅ 开机检测成功，跳过延时")
                else:
                    print("⚠️ 开机检测超时，使用标准延时")
                    if self.serial_controller.relay_open_delay_ms > 0:
                        time.sleep(self.serial_controller.relay_open_delay_ms / 1000)  # 继电器开启后延时
            else:
                if self.serial_controller.relay_open_delay_ms > 0:
                    time.sleep(self.serial_controller.relay_open_delay_ms / 1000)  # 继电器开启后延时
        
        # 主题级别的循环
        loop = 0
        is_infinite = actual_loop_count == -1
        
        # 更新显示信息
        if is_infinite:
            print(f"📊 指令数: {total_commands}, 主题无限循环, 间隔: {actual_loop_delay}ms")
        else:
            print(f"📊 指令数: {total_commands}, 主题循环: {actual_loop_count}次, 间隔: {actual_loop_delay}ms")
        
        while is_infinite or loop < actual_loop_count:
            if actual_loop_count > 1 or is_infinite:
                if is_infinite:
                    print(f"\n🔄 第 {loop + 1} 次主题循环 (无限循环)")
                else:
                    print(f"\n🔄 第 {loop + 1}/{actual_loop_count} 次主题循环")
                if loop > 0 and actual_loop_delay > 0:
                    time.sleep(actual_loop_delay / 1000)
            
            # 执行每条指令，支持指令级别的循环
            for i, cmd in enumerate(topic.commands):
                cmd_loop_count = cmd.get('loop_count', 1)
                
                # 指令级别的循环执行
                for cmd_loop in range(cmd_loop_count):
                    try:
                        # 仅在第一次循环时显示指令开始信息
                        if cmd_loop == 0:
                            if cmd_loop_count > 1:
                                print(f"🔄 执行指令 {i+1}/{total_commands}: {cmd['command']} (共{cmd_loop_count}次)")
                            else:
                                print(f"🔄 执行指令 {i+1}/{total_commands}: {cmd['command']}")
                        
                        # 记录发送时间
                        send_time = datetime.now()
                        
                        # 发送指令并获取响应
                        response = self.send_command(cmd['command'], cmd['delay_ms'])
                        
                        # 检查响应是否为空（模组无响应）
                        response_clean = response.strip()
                        if not response_clean or response_clean == "❌ 未连接端口":
                            # 获取当前连接信息用于诊断
                            port_info = "未知端口"
                            baud_info = "未知波特率"
                            if hasattr(self, 'serial_controller') and self.serial_controller.serial_port:
                                port = self.serial_controller.serial_port
                                if port and port.is_open:
                                    port_info = port.name
                                    baud_info = str(port.baudrate)
                            
                            print(f"\n❌ 模组无响应 - 通信失败")
                            print(f"📡 当前连接: {port_info}@{baud_info}")
                            print(f"🔍 可能原因:")
                            print(f"   • 波特率不匹配 (当前: {baud_info})")
                            print(f"   • 模组未开机或已关机")
                            print(f"   • 串口线连接问题")
                            print(f"   • 模组处于异常状态")
                            print(f"\n💡 建议操作:")
                            print(f"   1. 检查模组是否开机")
                            print(f"   2. 确认波特率设置 (常用: 9600, 115200)")
                            print(f"   3. 重新插拔串口线")
                            print(f"   4. 重启模组")
                            
                            result = {
                                "topic": topic_name,
                                "loop": loop + 1,
                                "command": cmd['command'],
                                "delay_ms": cmd['delay_ms'],
                                "cmd_loop": cmd_loop + 1,
                                "cmd_loop_total": cmd_loop_count,
                                "send_time": datetime.now().isoformat(),
                                "response": "",
                                "error": f"模组无响应 - 通信失败 (端口: {port_info}, 波特率: {baud_info})",
                                "success": False
                            }
                            results.append(result)
                            return results
                        
                        # 检查响应是否包含OK
                        is_success = "OK" in response_clean and "ERROR" not in response_clean
                        
                        # 解析数据
                        parsed_data = self.parse_response(response, topic.parse_patterns)
                        
                        result = {
                            "topic": topic_name,
                            "loop": loop + 1,
                            "command": cmd['command'],
                            "delay_ms": cmd['delay_ms'],
                            "cmd_loop": cmd_loop + 1,
                            "cmd_loop_total": cmd_loop_count,
                            "send_time": send_time.isoformat(),
                            "response": response_clean,
                            "parsed_data": parsed_data,
                            "success": is_success
                        }
                        
                        results.append(result)
                        
                        # 简洁状态显示
                        status_icon = "✅" if is_success else "❌"
                        status_color = "🟢" if is_success else "🔴"
                        
                        # 简化的响应摘要
                        response_summary = response_clean.replace('\r\n', ' ').replace('\n', ' ').strip()
                        if len(response_summary) > 50:
                            response_summary = response_summary[:47] + "..."
                        
                        # 构建简洁统计
                        stats = ""
                        if "OK" in response_clean:
                            stats += " ✓"
                        if "ERROR" in response_clean:
                            stats += " ⚠"
                        
                        # 指令编号
                        cmd_id = f"{i+1}.{cmd_loop+1}" if cmd_loop_count > 1 else f"{i+1}"
                        
                        # 简洁输出格式
                        print(f"📡 {cmd_id}: {cmd['command']} → {status_color}{status_icon}{stats} {response_summary}")
                        
                        # 解析数据（紧凑显示）
                        if parsed_data:
                            data_str = " | ".join([f"{k}:{v}" for k, v in parsed_data.items()])
                            print(f"   📊 {data_str}")
                        
                        # 如果失败且需要停止
                        if not is_success and response_clean:
                            result["error"] = "未收到OK响应"
                            if topic.stop_on_error:
                                print(f"🛑 主题配置为错误时停止，终止测试")
                                return results
                            break  # 停止当前指令的后续循环
                        
                        # 指令循环之间的延时（除了最后一次）
                        if cmd_loop < cmd_loop_count - 1 and cmd['delay_ms'] > 0:
                            time.sleep(cmd['delay_ms'] / 1000.0)
                        
                        # 每个指令循环后都检查紧急停止
                        if hasattr(self, 'emergency_stop_flag') and self.emergency_stop_flag:
                            print("🚨 检测到紧急停止信号，立即终止当前指令循环")
                            break
                    
                    except Exception as e:
                        error_msg = f"执行失败: {e}"
                        print(f"❌ {error_msg}")
                        results.append({
                            "topic": topic_name,
                            "loop": loop + 1,
                            "command": cmd['command'],
                            "delay_ms": cmd['delay_ms'],
                            "cmd_loop": cmd_loop + 1,
                            "cmd_loop_total": cmd_loop_count,
                            "send_time": send_time.isoformat() if 'send_time' in locals() else datetime.now().isoformat(),
                            "response": "",
                            "error": error_msg,
                            "success": False
                        })
                        if topic.stop_on_error:
                            return results
                        break  # 停止当前指令的后续循环
            
            loop += 1
            
            # 检查紧急停止标志
            if hasattr(self, 'emergency_stop_flag') and self.emergency_stop_flag:
                print("🚨 检测到紧急停止信号，立即终止测试")
                break
        
        # 测试完成后关闭继电器
        if self.serial_controller.relay_control_enabled and self.serial_controller.relay_close_after_loop:
            self.set_relay_state(False)
            if self.serial_controller.relay_close_delay_ms > 0:
                time.sleep(self.serial_controller.relay_close_delay_ms / 1000)  # 继电器关闭前延时
        
        self.test_results.extend(results)
        
        print(f"\n✅ 主题测试完成，共执行 {len(results)} 条指令")
        
        # 询问用户是否保存执行历史
        while True:
            save_choice = input("\n💾 是否保存执行历史？(Y/N): ").strip().upper()
            if save_choice in ['Y', 'YES']:
                self.save_execution_history(topic_name, results)
                print("📊 执行历史已保存")
                break
            elif save_choice in ['N', 'NO']:
                print("⏭️  跳过保存")
                break
            else:
                print("❌ 请输入 Y 或 N")
        
        return results
    
    def parse_response(self, response: str, patterns: List[Dict]) -> Dict:
        """解析响应数据"""
        parsed = {}
        
        for pattern_info in patterns:
            try:
                match = re.search(pattern_info['pattern'], response)
                if match:
                    value = match.group(1)
                    
                    # 根据类型转换数据
                    if pattern_info['type'] == 'int':
                        value = int(value)
                    elif pattern_info['type'] == 'float':
                        value = float(value)
                    
                    parsed[pattern_info['name']] = value
                    
                    # VBAT监控处理
                    if self.vbat_monitor.vbat_monitor_enabled and pattern_info['name'].lower() in ['vbat', 'vbat_voltage']:
                        self.process_vbat_value(value)
                        # 立即检查是否触发了紧急停止
                        if hasattr(self, 'emergency_stop_flag') and self.emergency_stop_flag:
                            print("🚨 VBAT警告触发紧急停止，立即终止当前处理")
                            return parsed  # 提前返回，停止后续处理
                        
            except Exception as e:
                print(f"⚠️ 解析失败 {pattern_info['name']}: {e}")
        
        return parsed

    def process_vbat_value(self, vbat_value):
        """处理VBAT值并检查阈值"""
        self.vbat_monitor.process_vbat_value(vbat_value, self)

    def send_vbat_mqtt_alert(self, vbat_mv, alert_type):
        """发送VBAT MQTT告警（支持自定义指令模板）"""
        self.vbat_monitor.send_vbat_mqtt_alert(vbat_mv, alert_type, self)

    def parse_mqtt_at_command(self, command_str, command_type):
        """智能解析MQTT相关AT指令，提取参数并生成模板
        
        支持解析以下格式的AT指令：
        - 连接: AT+ECMTOPEN=0,"test.mosquitto.org",1883
        - 订阅: AT+ECMTSUB=0,1,"/lierda/test",2
        - 发布: AT+ECMTPUB=0,0,0,0,"/lierda/test","{\"vbat\":3700}"
        - 断开: AT+ECMTDISC=0
        
        Args:
            command_str (str): 实际的AT指令字符串
            command_type (str): 指令类型 ('connect', 'subscribe', 'publish', 'disconnect')
            
        Returns:
            dict: 包含解析结果的字典，失败返回None
        """
        try:
            # 使用独立的解析器模块处理指令解析
            return self.at_parser.parse_mqtt_command(command_str, command_type)
        except Exception as e:
            print(f"❌ 指令解析失败: {e}")
            return None

    def view_vbat_records(self):
        """查看VBAT记录"""
        self.vbat_monitor.view_vbat_records()

    def export_vbat_data(self):
        """导出VBAT数据"""
        self.vbat_monitor.export_vbat_data()
    
    def save_named_config(self, named_config):
        """保存命名配置"""
        self.vbat_monitor.save_named_config(named_config)
    
    def load_named_configs(self):
        """加载所有命名配置"""
        return self.vbat_monitor.load_named_configs()
    
    def apply_named_config(self, config_name):
        """应用指定名称的配置"""
        return self.vbat_monitor.apply_named_config(config_name)
    
    def delete_named_config(self, config_name):
        """删除指定名称的配置"""
        return self.vbat_monitor.delete_named_config(config_name)
    
    def show_named_configs(self):
        """显示所有命名配置"""
        return self.vbat_monitor.show_named_configs()
    
    def manage_named_configs(self):
        """管理命名配置"""
        self.vbat_monitor.manage_named_configs()
    
    def save_test_results(self, topic_name: str, custom_filename: str = None):
        """保存测试结果"""
        # 过滤当前主题的结果
        topic_results = [r for r in self.test_results if r.get("topic") == topic_name]
        
        if not topic_results:
            print(f"⚠️ 主题 '{topic_name}' 没有测试结果")
            return
        
        # 生成文件名
        if custom_filename:
            base_filename = custom_filename
        else:
            base_filename = topic_name
        
        # 检查文件是否存在，如果存在则添加时间戳
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        csv_filename = f"{base_filename}_{timestamp}.csv"
        json_filename = f"{base_filename}_{timestamp}.json"
        
        try:
            # 保存CSV
            with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile:
                # 获取所有可能的字段
                all_fields = set()
                for result in topic_results:
                    all_fields.update(result.keys())
                    if 'parsed_data' in result and result['parsed_data']:
                        all_fields.update(result['parsed_data'].keys())
                
                # 固定字段顺序
                fieldnames = ['topic', 'command', 'delay_ms', 'send_time', 'response']
                parsed_fields = [f for f in all_fields if f not in fieldnames]
                fieldnames.extend(parsed_fields)
                
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                writer.writeheader()
                
                for result in topic_results:
                    row = result.copy()
                    if 'parsed_data' in result and result['parsed_data']:
                        row.update(result['parsed_data'])
                        del row['parsed_data']
                    writer.writerow(row)
            
            # 保存JSON
            with open(json_filename, 'w', encoding='utf-8') as f:
                json.dump(topic_results, f, ensure_ascii=False, indent=2)
            
            print(f"✅ 数据已保存:")
            print(f"   CSV: {csv_filename}")
            print(f"   JSON: {json_filename}")
            
        except Exception as e:
            print(f"❌ 保存数据失败: {e}")

def clear_screen():
    """清屏函数"""
    import os
    os.system('cls' if os.name == 'nt' else 'clear')

def main():
    controller = AdvancedATController()
    
    clear_screen()
    print("🚀 高级端口AT指令控制器")
    print("="*60)
    
    # 连接端口
    while True:
        ports_info = controller.list_available_ports_with_info()
        if not ports_info:
            print("❌ 没有找到可用的端口，正在重新检测...")
            time.sleep(2)  # 短暂等待后自动重试
            continue
        
        print("🔍 可用端口:")
        print("=" * 50)
        port_map = {}
        for port_info in ports_info:
            device = port_info['device']
            # 提取数字部分，如COM3 -> 3
            port_num = ''.join(filter(str.isdigit, device))
            port_map[port_num] = device
            print(f"{port_num} - {device} - {port_info['description']}")
        print("=" * 50)
        
        try:
            port_num = input("\n请输入端口号数字: ").strip()
            if port_num == '0':
                print("❌ 用户取消，程序退出")
                return
            
            # 验证端口号数字是否有效
            if port_num not in port_map:
                available_nums = list(port_map.keys())
                print(f"❌ 端口 {port_num} 当前不可用")
                print("可用的端口号数字:", ", ".join(available_nums))
                continue
            
            selected_port = port_map[port_num]
        except KeyboardInterrupt:
            print("\n❌ 用户取消，程序退出")
            return
        except Exception as e:
            print(f"❌ 输入错误: {e}")
            continue
        
        # 选择波特率并连接
        if controller.connect_with_baudrate_selection(selected_port):
            break  # 连接成功，退出循环
        # 连接失败，自动返回端口选择界面

    # 主菜单
    while True:
        clear_screen()
        print("🎯 高级AT指令控制器主菜单")
        print("="*60)
        # 获取当前连接的端口描述信息
        port_info_list = controller.list_available_ports_with_info()
        port_desc = '未知设备'
        for info in port_info_list:
            if info['device'] == selected_port:
                port_desc = info['description']
                break
        
        # 获取当前波特率
        current_baudrate = 0
        if hasattr(controller.serial_controller, 'serial_port') and controller.serial_controller.serial_port:
            current_baudrate = controller.serial_controller.serial_port.baudrate
        
        baudrate_display = f"@{current_baudrate}" if current_baudrate > 0 else ""
        print(f"📡 当前连接: {selected_port}{baudrate_display} ({port_desc})")
        print(f"📊 已加载主题: {len(controller.topic_manager.get_all_topics())} 个")
        print()
        print("1. 📋 查看主题列表")
        print("2. 🧪 运行主题测试")
        print("3. ⚙️  配置解析模式")
        print("4. 💾 保存测试结果")
        print("5. 📝 主题管理")
        print("6. 📊 查看执行历史")
        print("7. 🔌 继电器控制")
        print("8. 🔋 VBAT监控")
        print("9. ❌ 退出")
        print()
        
        choice = input("请选择操作 (1-9): ").strip()
        
        if choice == '1':
            # 查看主题
            while True:
                clear_screen()
                print("📋 主题列表")
                print("="*30)
                
                topics = list(controller.topic_manager.get_all_topics().keys())
                if not topics:
                    print("⚠️ 没有可用的主题")
                    input("按回车键返回主菜单...")
                    break
                
                controller.list_topics()
                
                print("\n选项:")
                print("1. 查看某个主题详细内容")
                print("2. 返回")
                
                sub_choice = input("请选择 (1-2): ").strip()
                
                if sub_choice == "1":
                    try:
                        topic_choice = int(input("请输入主题序号: ").strip()) - 1
                        if 0 <= topic_choice < len(topics):
                            name = topics[topic_choice]
                            controller.view_topic_details(name)
                            input("\n按回车键返回主题列表...")
                        else:
                            print("❌ 序号无效")
                            input("按回车键返回...")
                    except ValueError:
                        print("❌ 请输入有效数字")
                        input("按回车键返回...")
                elif sub_choice == "2":
                    break
        elif choice == '2':
            # 运行主题测试
            while True:
                clear_screen()
                print("🧪 运行主题测试")
                print("="*30)
                
                topics = controller.topic_manager.get_all_topics()
                if not topics:
                    print("⚠️ 没有可用的主题")
                    input("按回车键返回主菜单...")
                    break
                    
                topics_list = list(topics.keys())
                for i, name in enumerate(topics_list, 1):
                    topic = topics[name]
                    cmd_count = len(topic.commands)
                    pattern_count = len(topic.parse_patterns)
                    print(f"{i}. 📁 {name} ({cmd_count}条指令, {pattern_count}个解析模式)")
                
                try:
                    topic_choice = int(input("请选择主题序号: ").strip()) - 1
                    if 0 <= topic_choice < len(topics_list):
                        name = topics_list[topic_choice]
                        loop_input = input("请输入循环次数(-1为无限循环,默认1): ").strip()
                        loop_count = int(loop_input) if loop_input else 1
                        if loop_count > 1 or loop_count == -1:
                            if loop_count == -1:
                                print("⚠️  无限循环模式，请确保有停止条件！")
                            else:
                                print("⚠️  多次循环时，间隔时间务必谨慎选择！")
                                print("   建议从500ms开始，根据设备响应调整")
                        loop_delay = int(input("请输入循环间隔ms(默认500): ").strip() or "500")
                        
                        clear_screen()
                        print(f"🚀 开始运行: {name}")
                        print("="*40)
                        controller.run_topic_test(name, loop_count, loop_delay)
                        
                        input("\n✅ 测试完成！按回车键返回测试菜单...")
                    else:
                        print("❌ 序号无效")
                        input("按回车键返回...")
                except ValueError:
                    print("❌ 请输入有效数字")
                    input("按回车键返回...")
                
                # 询问是否继续测试其他主题
                continue_choice = input("是否继续测试其他主题? (y/n): ").strip().lower()
                if continue_choice != 'y':
                    break
        elif choice == '3':
            # 配置解析模式
            while True:
                clear_screen()
                print("⚙️  配置解析模式")
                print("="*30)
                
                topics = controller.topic_manager.get_all_topics()
                if not topics:
                    print("⚠️ 没有可用的主题")
                    input("按回车键返回主菜单...")
                    break
                    
                topics_list = list(topics.keys())
                for i, name in enumerate(topics_list, 1):
                    topic = topics[name]
                    pattern_count = len(topic.parse_patterns)
                    print(f"{i}. 📁 {name} ({pattern_count}个解析模式)")
                
                try:
                    topic_choice = int(input("请选择主题序号: ").strip()) - 1
                    if 0 <= topic_choice < len(topics_list):
                        name = topics_list[topic_choice]
                        controller.configure_parse_patterns(name)
                        input("\n✅ 配置完成！按回车键返回解析模式菜单...")
                    else:
                        print("❌ 序号无效")
                        input("按回车键返回...")
                except ValueError:
                    print("❌ 请输入有效数字")
                    input("按回车键返回...")
                
                # 询问是否继续配置其他主题
                continue_choice = input("是否继续配置其他主题? (y/n): ").strip().lower()
                if continue_choice != 'y':
                    break
        elif choice == '4':
            # 保存测试结果
            while True:
                clear_screen()
                print("💾 保存测试结果")
                print("="*30)
                
                if not controller.test_results:
                    print("⚠️  没有测试结果可保存")
                    input("按回车键返回主菜单...")
                    break
                    
                topics_with_results = set(r.get("topic") for r in controller.test_results)
                topics_list = list(topics_with_results)
                
                for i, name in enumerate(topics_list, 1):
                    count = len([r for r in controller.test_results if r.get("topic") == name])
                    print(f"{i}. 📊 {name} ({count}条结果)")
                
                try:
                    topic_choice = int(input("请选择主题序号: ").strip()) - 1
                    if 0 <= topic_choice < len(topics_list):
                        name = topics_list[topic_choice]
                        custom_name = input("请输入文件名(留空使用主题名): ").strip()
                        controller.save_test_results(name, custom_name or None)
                        input("按回车键返回保存结果菜单...")
                    else:
                        print("❌ 序号无效")
                        input("按回车键返回...")
                except ValueError:
                    print("❌ 请输入有效数字")
                    input("按回车键返回...")
                
                # 询问是否继续保存其他主题
                continue_choice = input("是否继续保存其他主题? (y/n): ").strip().lower()
                if continue_choice != 'y':
                    break
        elif choice == '5':
            # 主题管理
            while True:
                clear_screen()
                print("📝 主题管理")
                print("="*30)
                print("1. ➕ 创建新主题")
                print("2. 🗑️  删除主题")
                print("3. 👈 返回")
                
                sub_choice = input("请选择操作 (1-3): ").strip()
                
                if sub_choice == '1':
                    name = input("请输入主题名称: ").strip()
                    if name:
                        controller.create_topic(name)
                        input("✅ 主题已创建！按回车键返回主题管理菜单...")
                elif sub_choice == '2':
                    controller.list_topics()
                    name = input("请输入要删除的主题名称: ").strip()
                    if name:
                        controller.delete_topic(name)
                        input("✅ 主题已删除！按回车键返回主题管理菜单...")
                elif sub_choice == '3':
                    break
        elif choice == '6':
            # 查看执行历史
            controller.view_execution_history()
            input("按回车键返回主菜单...")
        elif choice == '7':
            # 继电器控制
            while True:
                clear_screen()
                print("🔌 继电器控制")
                print("="*30)
                print(f"当前状态: {'已启用' if controller.serial_controller.relay_control_enabled else '已禁用'}")
                if controller.serial_controller.relay_control_enabled:
                    print(f"激活电平: {'高电平' if controller.serial_controller.relay_active_level else '低电平'}")
                    print(f"循环前开启: {'是' if controller.serial_controller.relay_open_before_loop else '否'}")
                    print(f"循环后关闭: {'是' if controller.serial_controller.relay_close_after_loop else '否'}")
                    print(f"开启后延时: {controller.serial_controller.relay_open_delay_ms}ms")
                    print(f"关闭前延时: {controller.serial_controller.relay_close_delay_ms}ms")
                print()
                print("1. 配置继电器参数")
                print("2. 手动控制继电器")
                print("3. 查看当前配置")
                print("4. 返回")
                
                relay_choice = input("请选择操作 (1-4): ").strip()
                
                if relay_choice == '1':
                    controller.configure_relay_control()
                    input("按回车键返回继电器菜单...")
                elif relay_choice == '2':
                    if not (controller.serial_controller and controller.serial_controller.serial_port and controller.serial_controller.serial_port.is_open):
                        print("❌ 请先连接端口")
                    else:
                        current_state = controller.toggle_relay()
                        print(f"🔌 继电器状态已切换为{'打开' if current_state else '关闭'}")
                    input("按回车键返回继电器菜单...")
                elif relay_choice == '3':
                    print("\n📊 当前继电器配置:")
                    print(f"   状态: {'已启用' if controller.serial_controller.relay_control_enabled else '已禁用'}")
                    print(f"   激活电平: {'高电平' if controller.serial_controller.relay_active_level else '低电平'}")
                    print(f"   循环前开启: {'是' if controller.serial_controller.relay_open_before_loop else '否'}")
                    print(f"   循环后关闭: {'是' if controller.serial_controller.relay_close_after_loop else '否'}")
                    print(f"   开启后延时: {controller.serial_controller.relay_open_delay_ms}ms")
                    print(f"   关闭前延时: {controller.serial_controller.relay_close_delay_ms}ms")
                    input("按回车键返回继电器菜单...")
                elif relay_choice == '4':
                    break
        elif choice == '8':
            # VBAT监控
            while True:
                clear_screen()
                print("🔋 VBAT监控")
                print("="*30)
                
                # 获取当前连接的端口描述信息
                port_info_list = controller.list_available_ports_with_info()
                port_desc = '未知设备'
                for info in port_info_list:
                    if info['device'] == selected_port:
                        port_desc = info['description']
                        break
                
                # 获取当前波特率
                current_baudrate = 0
                if hasattr(controller.serial_controller, 'serial_port') and controller.serial_controller.serial_port:
                    current_baudrate = controller.serial_controller.serial_port.baudrate
                
                baudrate_display = f"@{current_baudrate}" if current_baudrate > 0 else ""
                print(f"📡 当前连接: {selected_port}{baudrate_display} ({port_desc})")
                print()
                print(f"状态: {'已启用' if controller.vbat_monitor.vbat_monitor_enabled else '已禁用'}")
                if controller.vbat_monitor.vbat_monitor_enabled:
                    print(f"低阈值: {controller.vbat_monitor.vbat_threshold_low}mV")
                    print(f"高阈值: {controller.vbat_monitor.vbat_threshold_high}mV")
                    print(f"记录数: {len(controller.vbat_monitor.vbat_records)}")
                    print(f"MQTT: {'已启用' if controller.vbat_monitor.vbat_mqtt_enabled else '已禁用'}")
                
                # 显示设备指令检测状态
                mqtt_count = len(controller.vbat_monitor._detected_mqtt_commands)
                mt_count = len(controller.vbat_monitor._detected_mt_commands)
                if mqtt_count > 0 or mt_count > 0:
                    print(f"指令检测: MQTT({mqtt_count}) MT({mt_count})")
                else:
                    print("指令检测: 未检测 (请选择选项5进行检测)")
                print()
                print("1. 配置VBAT监控")
                print("2. 查看VBAT记录")
                print("3. 导出VBAT数据")
                print("4. 管理命名配置")
                print("5. 检测设备指令")
                print("6. 返回")
                
                vbat_choice = input("请选择操作 (1-5): ").strip()
                
                if vbat_choice == '1':
                    controller.configure_vbat_monitor()
                    input("按回车键返回VBAT菜单...")
                elif vbat_choice == '2':
                    controller.view_vbat_records()
                    input("按回车键返回VBAT菜单...")
                elif vbat_choice == '3':
                    controller.export_vbat_data()
                    input("按回车键返回VBAT菜单...")
                elif vbat_choice == '4':
                    controller.manage_named_configs()
                    input("按回车键返回VBAT菜单...")
                elif vbat_choice == '5':
                    # 主动检测设备指令
                    if controller.serial_controller and controller.serial_controller.serial_port and controller.serial_controller.serial_port.is_open:
                        controller.vbat_monitor.detect_device_commands(controller)
                        input("\n按回车键返回VBAT菜单...")
                    else:
                        print("❌ 请先连接端口")
                        input("按回车键返回VBAT菜单...")
                elif vbat_choice == '6':
                    break
        elif choice == '9':
            controller.disconnect()
            print("👋 感谢使用，再见！")
            break
        else:
            print("❌ 无效选择")

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\n👋 用户中断，正在退出...")
        sys.exit(0)